package element.synt;

import ast.*;
import element.base.Synt;
import element.base.Word;
import element.base.WordType;

public class Stmt extends Synt {
    @Override
    public AstItem toAst() {
        if (findFirst().isWord(WordType.SEMICN)) {
            return null;
        } else if (findFirst().isWord(WordType.IFTK)) {
            StructuralStatement statement = new StructuralStatement();
            statement.type = Statement.StatementType.IF_STMT;
            Exp exp = (Exp) getNodes().get(2);
            statement.controlConditions.add(exp.toAst());
            Stmt state = (Stmt) getNodes().get(4);
            statement.state = state.toAst();

            if (getNodes().size() == 7) {
                Stmt stateElse = (Stmt) getNodes().getLast();
                statement.stateElse = stateElse.toAst();
            }

            return statement;
        } else if (findFirst().isWord(WordType.WHILETK)) {
            StructuralStatement statement = new StructuralStatement();
            statement.type = Statement.StatementType.WHILE_STMT;
            Exp exp = (Exp) getNodes().get(2);
            statement.controlConditions.add(exp.toAst());
            Stmt state = (Stmt) getNodes().getLast();
            statement.state = state.toAst();

            return statement;
        } else if (findFirst().isWord(WordType.FORTK)) {
            StructuralStatement statement = new StructuralStatement();
            statement.type = Statement.StatementType.FOR_STMT;

            int point = 2;

            SimpleStmt cond1 = (SimpleStmt) getNodes().get(point);
            statement.controlConditions.add(cond1.toAst());
            point += 2;

            if (getNodes().get(point).isWord(WordType.SEMICN)) {
                statement.controlConditions.add(null);
                point += 1;
            } else {
                Exp cond2 = (Exp) getNodes().get(point);
                statement.controlConditions.add(cond2.toAst());
                point += 2;
            }

            SimpleStmt cond3 = (SimpleStmt) getNodes().get(point);
            statement.controlConditions.add(cond3.toAst());

            Stmt state = (Stmt) getNodes().getLast();
            statement.state = state.toAst();

            return statement;
        } else if (findFirst().isWord(WordType.BREAKTK)) {
            JumpStatement statement = new JumpStatement();
            statement.type = Statement.StatementType.BREAK_STMT;
            return statement;
        } else if (findFirst().isWord(WordType.CONTINUETK)) {
            JumpStatement statement = new JumpStatement();
            statement.type = Statement.StatementType.CONTINUE_STMT;
            return statement;
        } else if (findFirst().isWord(WordType.RETURNTK)) {
            JumpStatement statement = new JumpStatement();
            statement.type = Statement.StatementType.RETURN_STMT;
            Exp returnData = (Exp) getNodes().get(1);
            statement.return_data = returnData.toAst();
            return statement;
        } else if (findFirst().isWord(WordType.PRINTTK)) {
            OutputStatement statement = new OutputStatement();
            String outputStr = ((Word) getNodes().get(2)).getContent();
            statement.printString = outputStr;
            statement.type = Statement.StatementType.PRINT_STMT;

            if (getNodes().size() != 5) {
                int formatCount = (getNodes().size() - 8) / 2;
                for (int i = 0; i < formatCount; i++) {
                    Exp formatData = (Exp) getNodes().get(2 * i + 6);
                    statement.formatExpressions.add(formatData.toAst());
                }
            }

            return statement;
        } else if (getNodes().getFirst().isSynt(Exp.class)) {
            Expression expression = (Expression) ((Exp) getNodes().getFirst()).toAst();
            LValStatement statement= new LValStatement();
            statement.type = Statement.StatementType.EXP_STMT;
            statement.RVal = expression;
            return statement;
        } else if (getNodes().getFirst().isSynt(Block.class)) {
            return ((Block) getNodes().getFirst()).toAst();
        } else {
            if (getNodes().get(2).isWord(WordType.INPUTTK)) {
                InputStatement statement = new InputStatement();
                statement.type = Statement.StatementType.INPUT_STMT;
                LVal lVal = (LVal) getNodes().getFirst();
                statement.LVal = lVal.toAst();
                if (getNodes().size() == 7) {
                    Word string = (Word) getNodes().get(4);
                    statement.promptString = string.getContent();
                }
                return statement;
            } else if (getNodes().get(1).isWord(WordType.ADD) &&
                    getNodes().get(2).isWord(WordType.ADD)) {
                LValStatement statement = new LValStatement();
                statement.type = Statement.StatementType.SELF_ADD_STMT;
                LVal lVal = (LVal) getNodes().getFirst();
                statement.LVal = lVal.toAst();
                return statement;
            } else if (getNodes().get(1).isWord(WordType.MINU) &&
                    getNodes().get(2).isWord(WordType.MINU)) {
                LValStatement statement = new LValStatement();
                statement.type = Statement.StatementType.SELF_MINU_STMT;
                LVal lVal = (LVal) getNodes().getFirst();
                statement.LVal = lVal.toAst();
                return statement;
            } else {
                LValStatement statement = new LValStatement();
                statement.type = Statement.StatementType.ASSIGN_STMT;
                LVal lVal = (LVal) getNodes().getFirst();
                statement.LVal = lVal.toAst();

                Assign assign = (Assign) getNodes().get(1);
                if (assign.findFirst().isWord(WordType.ASSIGN)) {
                    statement.assignType = LValStatement.AssignType.NORMAL;
                } else if (assign.findFirst().isWord(WordType.ADDASSIGN)) {
                    statement.assignType = LValStatement.AssignType.ADD;
                } else if (assign.findFirst().isWord(WordType.MINUASSIGN)) {
                    statement.assignType = LValStatement.AssignType.MINU;
                } else if (assign.findFirst().isWord(WordType.MULTASSIGN)) {
                    statement.assignType = LValStatement.AssignType.MULT;
                } else if (assign.findFirst().isWord(WordType.DIVASSIGN)) {
                    statement.assignType = LValStatement.AssignType.DIV;
                } else if (assign.findFirst().isWord(WordType.MODASSIGN)) {
                    statement.assignType = LValStatement.AssignType.MOD;
                }

                Expression expression = (Expression) ((Exp) getNodes().get(2)).toAst();
                statement.RVal = expression;
                return statement;
            }
        }
    }
}
